﻿using System;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Serialization;

namespace Deployment.Data.Variable
{
    public class VariableXmlSerializer<T> : IXmlSerializable where T : AbstractVariable
    {
        private const string TYPE_ATTRIB = "Type";
        private const string NAME_ATTRIB = "Name";
        private const string ENVIRONMENT_ATTRIB = "Environment";

        private const string EXTRA_ELEMENT = "Extra";
        private const string VALUE_ELEMENT = "Value";

        private T _variable;

        public VariableXmlSerializer() { }

        public VariableXmlSerializer(T variable)
        {
            this._variable = variable;
        }

        public T Variable
        {
            get { return _variable; }
            set { _variable = value; }
        }

        #region IXmlSerializable members

        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }

        public void ReadXml(System.Xml.XmlReader reader)
        {
            string ElementName = reader.Name;

            string typeAttribute = reader.GetAttribute(TYPE_ATTRIB);
            string nameAttribute = reader.GetAttribute(NAME_ATTRIB);
            string envAttribute = reader.GetAttribute(ENVIRONMENT_ATTRIB);

            //Now Read the Elements in this node;
            string valueElement = null;
            string extraElement = null;
            while (true)
            {
                reader.Read();
                if (reader.NodeType == XmlNodeType.Element)
                {
                    if (reader.Name.Equals(VALUE_ELEMENT, StringComparison.CurrentCultureIgnoreCase))
                    {
                        valueElement = reader.ReadElementContentAsString();
                    }
                    else if (reader.Name.Equals(EXTRA_ELEMENT, StringComparison.CurrentCultureIgnoreCase))
                    {
                        extraElement = reader.ReadElementContentAsString();
                    }
                }
                else if (reader.NodeType == System.Xml.XmlNodeType.EndElement && reader.Name.Equals(ElementName))
                {
                    break;
                }
            }

            if (string.IsNullOrEmpty(typeAttribute))
                throw new ArgumentException("Unable to reader xml data for abstract type [" + typeof(T).Name +
                    "] because no 'Type' attribute was not specified in the element.");

            Type type = Type.GetType(typeAttribute);
            if (type == null)
                throw new InvalidCastException("Unable to create Task of type [" + typeAttribute + "], because it was not found.");

            if (!type.IsSubclassOf(typeof(T)))
                throw new InvalidCastException("Connection of type [" + type.Name + "] cannot be used because it does not inherit from " + typeof(T).Name + ".");

            //Create the type
            T obj = (T)Activator.CreateInstance(type);
            obj.Name = nameAttribute;
            obj.EnvironmentName = envAttribute;

            
            Variable = obj;
        }

        public void WriteXml(System.Xml.XmlWriter writer)
        {
            Type type = Variable.GetType();

            writer.WriteAttributeString(TYPE_ATTRIB, type.AssemblyQualifiedName);
            writer.WriteAttributeString(NAME_ATTRIB, Variable.Name);
            writer.WriteAttributeString(ENVIRONMENT_ATTRIB, Variable.EnvironmentName);

            writer.WriteElementString(VALUE_ELEMENT, Variable.Value);
            writer.WriteElementString(EXTRA_ELEMENT, Variable.Extra);

        }

        #endregion

        public static implicit operator T(VariableXmlSerializer<T> o)
        {
            return o.Variable;
        }

        public static implicit operator VariableXmlSerializer<T>(T o)
        {
            return o == null ? null : new VariableXmlSerializer<T>(o);
        }
    }
}
